#include "idxDivider.h"

extern Globs g;
extern Stats s;

int IdxDivider::load(int level) {
  m_ofid = 0;
  char fname[NAME_LEN];
  num_links_dump = 0;
  tsign_low = 0;

  sprintf(fname, "%s/%s.%d.0", 
      g.out_data_path,
      INDEX1_NAME,
      level);
  m_fp1 = fopen(fname, "w");
  if(m_fp1 == NULL) {
    FATAL("error fopen[%s]", fname);
    return E_RET;
  }

  sprintf(fname, "%s/%s.%d.0",
      g.out_data_path,
      INDEX0_NAME,
      level);
  m_fp0 = fopen(fname, "w");
  if(m_fp0 == NULL) {
    FATAL("error fopen[%s]", fname);
    return E_RET;
  }

  m_level = level;
  foff_in_index1 = 0;
  return S_RET;
}

int IdxDivider::start_divide(char* fname, int level_num) {
  int fid = 0;
  char invfname[NAME_LEN];
  idx_head_t head;
  int ret;
  FILE* fp;
  idx_index1_t index1;

  //open first
  sprintf(invfname, "%s.0", fname);
  FILE* invfp = fopen(invfname, "r");
  if(invfp == NULL) {
    FATAL("error fopen [%s]", invfname);
    return E_RET;
  }
  fclose(invfp);

  while(1) {
    sprintf(invfname, "%s.%d", fname, fid);
    NOTICE("start to fopen [%s]", invfname);
    fp = fopen(invfname, "r");
    if(fp == NULL) {
      NOTICE("finish at [%s] total_num[%d]", invfname, s.inv_fnum[level_num]);
      break;
    }
    while(1) {
      ret = fread(&head, sizeof(idx_head_t), 1, fp);
      if(ret != 1) {
        if(feof(fp)) {
	  s.inv_fnum[level_num]++;
	  fid++;
	  break;
	}
	else assert(0);
      }

      index1.tsign = head.tsign;
      index1.fno   = fid;
      index1.foff  = ftell(fp) - sizeof(idx_head_t);

      write_index1(&index1);

      ret = fseek(fp, 
	  ( 
	   head.num_idx * sizeof(idx_index_t) + 
	   head.num_idx * sizeof(idx_count_t) +
	   head.num_off * sizeof(offset_t)),
	   SEEK_CUR
	  ); assert(ret == 0);
    }
  }

  write_index1_last(&index1);
  

  return S_RET;
}

void IdxDivider::write_index1(idx_index1_t* pindex1) {
 // NOTICE("dump index1 tsign[%llu] fno[%d] foff[%d]", 
 //     pindex1->tsign, 
 //     pindex1->fno,
 //     pindex1->foff);
  int ret;
  idx_index0_t index0;

  ret = fwrite(pindex1, sizeof(idx_index1_t), 1, m_fp1);
  assert(ret == 1); 

  if(num_links_dump % NUM_LINKS_PER_INDEX0_BLOCK == 0) {
    if(num_links_dump == 0) {
      tsign_low = pindex1->tsign;
    }
    else {
      //dump index0
      index0.tsign_h = pindex1->tsign;
      index0.tsign_l = tsign_low;
      index0.foff_in_index1 = foff_in_index1;
      index0.fno_index1 = 0;

      DEBUG("dump index0: l[%llu] h[%llu] off[%u]",
          index0.tsign_l,
          index0.tsign_h,
          index0.foff_in_index1);
      ret = fwrite(&index0, sizeof(idx_index0_t), 1, m_fp0);
      assert(ret == 1);

      foff_in_index1 = ftell(m_fp1);
    }
  }
  else if((num_links_dump - 1) % NUM_LINKS_PER_INDEX0_BLOCK == 0 &&
      num_links_dump != 1) {
    tsign_low = pindex1->tsign;
  }
  num_links_dump++;
}

void IdxDivider::write_index1_last(idx_index1_t* pindex1) {
  int ret;
  idx_index0_t index0;

  index0.tsign_h = pindex1->tsign;
  index0.tsign_l = tsign_low;
  index0.foff_in_index1 = foff_in_index1;
  index0.fno_index1 = 0;

  DEBUG("dump index0: l[%llu] h[%llu] off[%u]",
      index0.tsign_l,
      index0.tsign_h,
      index0.foff_in_index1);
  ret = fwrite(&index0, sizeof(idx_index0_t), 1, m_fp0);
  assert(ret == 1);
}
